#include "comm.h"
#include "car_test.h"

static comm_tcb_t tcp_tcb;

void *tcp_thread(void *pdata)
{
    int ret;
    cJSON *recvjson;
    socklen_t clientAddrLen;
    struct sockaddr_in serverAddr;

    pdata = pdata;

    memset(&tcp_tcb, 0, sizeof(comm_tcb_t));
    memset(&serverAddr, 0, sizeof(serverAddr));

    tcp_tcb.sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // TCP socket 

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(3861);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    ret = bind(tcp_tcb.sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (ret < 0) {
        printf("bind failed, %d!\r\n", ret);
        close(tcp_tcb.sockfd);
    }
    printf("bind scockfd ok  %d\r\n", ret); 

    ret = listen(tcp_tcb.sockfd, 10);
    if (ret < 0) {
        printf("listen failed, %d!\r\n", ret);
        close(tcp_tcb.sockfd);
    }


    printf("===== waiting for client's request =====\r\n"); 
    while(1)
    {
        char *pClientIP;
        struct sockaddr_in addrClient;
        clientAddrLen = sizeof(addrClient);

        tcp_tcb.connfd = accept(tcp_tcb.sockfd, (struct sockaddr *)&addrClient, &clientAddrLen);    
        if(tcp_tcb.connfd < 0)
        {
            printf("accept socket error: %s(errno: %d)\r\n", strerror(errno), errno);
            close(tcp_tcb.sockfd);
        }
        pClientIP = inet_ntoa(addrClient.sin_addr);
        printf("client ip: %s, port: %d\r\n", pClientIP, ntohs(addrClient.sin_port));

        while(1)
        {
            memset(tcp_tcb.recvline, 0, sizeof(tcp_tcb.recvline));

            int len = recv(tcp_tcb.connfd, tcp_tcb.recvline, MAXLINE, 0);
            tcp_tcb.recvline[len] = '\0';

            //客户端发送exit或者异常结束时，退出
            if(strcmp(tcp_tcb.recvline, "exit\n")==0 || len<=0) {
                printf("client exit\r\n");
                break;
            }

            printf("\r\n recv data: \r\n");
            printf("%s\r\n", tcp_tcb.recvline);

            //进行json解析
            recvjson = cJSON_Parse(tcp_tcb.recvline);

            if(recvjson != NULL)
            {
                
                if(cJSON_GetObjectItem(recvjson, "cmd")->valuestring != NULL)
                {
                    printf("cmd : %s\r\n", cJSON_GetObjectItem(recvjson, "cmd")->valuestring);
                    
                    if(strcmp("forward", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        //ǰ��
                        printf("car forward");
                        set_car_status(CAR_STATUS_FORWARD);
                    }

                    if(strcmp("backward", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        //����
                        printf("car backward");
                        set_car_status(CAR_STATUS_BACKWARD);
                    }

                    if(strcmp("left", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        //��ת
                        printf("car left");
                        set_car_status(CAR_STATUS_LEFT);
                    }

                    if(strcmp("right", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        //��ת
                        printf("car right");
                        set_car_status(CAR_STATUS_RIGHT);
                    }

                    if(strcmp("stop", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        //ֹͣ
                        printf("car stop");
                        set_car_status(CAR_STATUS_STOP);
                    }
                }
                
                if(cJSON_GetObjectItem(recvjson, "mode")->valuestring != NULL)
                {
                    if(strcmp("step", cJSON_GetObjectItem(recvjson, "mode")->valuestring) == 0)
                    {
                        set_car_mode(CAR_MODE_STEP);
                        printf("mode step\r\n");
                    }

                    if(strcmp("alway", cJSON_GetObjectItem(recvjson, "mode")->valuestring) == 0)
                    {
                        set_car_mode(CAR_MODE_ALWAY);
                        printf("mode alway\r\n");
                    }
                } 

                // if(cJSON_GetObjectItem(recvjson, "proto")->valuestring != NULL)
                // {
                //     if(strcmp("tcp", cJSON_GetObjectItem(recvjson, "proto")->valuestring) == 0)
                //     {
                //         printf("======== Protocol: TCP ========\r\n");
                //         set_comm_mode(COMM_PROTOCOL_TCP);
                //     }

                //     if(strcmp("udp", cJSON_GetObjectItem(recvjson, "proto")->valuestring) == 0)
                //     {
                //         printf("======== Protocol: UDP ========\r\n");
                //         set_comm_mode(COMM_PROTOCOL_UDP);
                //     }
                // }

                cJSON_Delete(recvjson);
            }    
        }
        
        osDelay(1);
    }
    close(tcp_tcb.connfd);
    close(tcp_tcb.sockfd);
    return NULL;
}


void start_tcp_thread(void)
{
    osThreadAttr_t attr;

    attr.name = "tcp_thread";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 2048;
    attr.priority = 36;
    tcp_tcb.tcp_thd = osThreadNew((osThreadFunc_t)tcp_thread, NULL, &attr);

    if (tcp_tcb.tcp_thd == NULL) {
        printf("[tcp_thread] Falied to create tcp_thread!\n");
        return;
    }
    printf("[tcp_thread] Success to create tcp_thread!\n");
}


void cancel_tcp_thread(void)
{
    if(tcp_tcb.tcp_thd != NULL){
        printf("cancel_udp_thread\r\n");
        if(tcp_tcb.connfd != 0) {
            close(tcp_tcb.connfd);
        }
        
        if(tcp_tcb.sockfd != 0) {
            close(tcp_tcb.sockfd);
        }

        osThreadTerminate(tcp_tcb.tcp_thd);
        printf("[tcp_thread] cancel tcp_thread!\n");
        return;
    }
    printf("[tcp_thread] tcp_thread not live!\n");
}
